package main

import (
	"bufio"
	"flag"
	"fmt"
	"log"
	"os"
	"strings"
	"sync"
	"time"
)

const (
	TTY_USB1   = "/dev/ttyUSB1"
	NET_USB0   = "/sys/class/net/usb0"
	AT         = "AT"
	CPIN       = "+CPIN"
	CFUN       = "+CFUN"
	CIMI       = "+CIMI"
	ICCID      = "+ICCID"
	COPS       = "+COPS"
	CGSN       = "+CGSN"
	CSQ        = "+CSQ"
	CRCN       = "\r\n"
	QUESTION   = "?"
	QCRMCALL   = `\$QCRMCALL=1,1`
	QCRMUNCALL = `\$QCRMCALL=0,1`
)

type g4para struct {
	cpinState  string
	cfunState  string
	cimiState  string
	iccidState string
	cgsnState  string
	csqState   string
	copsState  string
}

type call4gInfo struct {
	usb0file  *os.File
	read      *bufio.Reader
	write     *bufio.Writer
	CurrCmd   string
	Recvflag  int
	Retrytime int
	Cmdmut    sync.RWMutex
	Para      g4para
	respChan  chan string // 用于接收响应
	stopChan  chan bool   // 用于停止读取goroutine
	isRunning bool
}

func CheckDeviceType(devicePath string) (string, error) {
	fileInfo, err := os.Lstat(devicePath)
	if err != nil {
		return "", err
	}

	mode := fileInfo.Mode()
	switch {
	case mode&os.ModeCharDevice != 0:
		return "字符设备", nil
	case mode&os.ModeDevice != 0:
		return "块设备", nil
	default:
		return "普通文件", nil
	}
}

func CheckDirectoryExists(dirPath string) (bool, error) {
	fileInfo, err := os.Stat(dirPath)
	if err != nil {
		if os.IsNotExist(err) {
			return false, nil
		}
		return false, err
	}

	return fileInfo.IsDir(), nil
}

var callMng call4gInfo

var cmd = flag.String("c", "i", "command: i(info), c(call), u(uncall)")

func main() {
	flag.Parse()
	callMng.Retrytime = 3
	deviceType, err := CheckDeviceType(TTY_USB1)
	if err != nil {
		fmt.Println("检查设备类型错误:", err)
	} else {
		fmt.Println("设备类型:", deviceType)
	}

	exists, err := CheckDirectoryExists(NET_USB0)
	if err != nil {
		fmt.Println("检查目录错误:", err)
	} else {
		fmt.Println("目录存在:", exists)
	}

	if err := TtyUsb1Open(TTY_USB1); err != nil {
		log.Fatalf("打开设备失败: %v", err)
	}

	go TtyUsb1Read()

	// 等待读取goroutine启动
	time.Sleep(100 * time.Millisecond)

	switch *cmd {
	case "i":
		TtyUsb1GetInfo()
	case "c":
		TtyUsb1Call()
	case "u":
		TtyUsb1Uncall()
	default:
		fmt.Printf("未知命令: %s\n", *cmd)
	}

	// 等待操作完成
	time.Sleep(3 * time.Second)

	// 清理资源
	TtyUsb1Close()
}

// TtyUsb1Read 改进的读取函数
func TtyUsb1Read() {
	callMng.isRunning = true
	defer func() {
		callMng.isRunning = false
		if callMng.usb0file != nil {
			callMng.usb0file.Close()
		}
	}()

	for {
		select {
		case <-callMng.stopChan:
			fmt.Println("停止读取goroutine")
			return
		default:
			// 设置读取超时
			callMng.usb0file.SetReadDeadline(time.Now().Add(2 * time.Second))

			// 尝试读取一行
			response, err := callMng.read.ReadBytes('\n')
			if err != nil {
				if os.IsTimeout(err) {
					// 读取超时，继续循环
					continue
				}
				if callMng.isRunning {
					log.Printf("读取错误: %v", err)
				}
				return
			}

			if len(response) == 0 {
				continue
			}
			contains := strings.Contains(string(response), "+CIEV:")
			if contains {
				continue
			}
			// 处理响应
			responseStr := strings.TrimSpace(string(response))
			fmt.Printf("收到响应: %s\n", responseStr)
			// 解析响应数据
			b := parseResponse(responseStr)
			if b == true {
				// 如果有等待的命令响应，发送到通道
				if callMng.Recvflag == 1 {
					select {
					case callMng.respChan <- responseStr:
						// 成功发送到通道
					default:
						// 通道已满，丢弃数据
					}
				}
			}
		}
	}
}

// parseResponse 解析AT命令响应
func parseResponse(response string) bool {
	if len(response) <= 2 {
		return false
	}

	callMng.Cmdmut.Lock()
	defer callMng.Cmdmut.Unlock()

	// 移除可能的回车换行符
	response = strings.Replace(response, "\r\n", "", -1)
	response = strings.Replace(response, "\n", "", -1)

	// 检查最终响应
	if response == "OK" || response == "ERROR" {
		callMng.Recvflag = 0
		return false
	}

	// 解析具体命令响应
	split := strings.Split(response, ":")
	if len(split) < 1 {
		return false
	}

	switch callMng.CurrCmd {
	case CPIN:
		if len(split) > 1 {
			callMng.Para.cpinState = strings.TrimSpace(split[1])
		}
	case CFUN:
		if len(split) > 1 {
			callMng.Para.cfunState = strings.TrimSpace(split[1])
		}
	case CIMI:
		callMng.Para.cimiState = strings.TrimSpace(split[0])
	case ICCID:
		if len(split) > 1 {
			callMng.Para.iccidState = strings.TrimSpace(split[1])
		}
	case COPS:
		if len(split) > 1 {
			subsplit := strings.Split(split[1], ",")
			if len(subsplit) > 2 {
				// 移除引号
				callMng.Para.copsState = strings.Trim(subsplit[2], "\"")
			}
		}
	case CSQ:
		if len(split) > 1 {
			callMng.Para.csqState = strings.TrimSpace(split[1])
		}
	case CGSN:
		callMng.Para.cgsnState = strings.TrimSpace(split[0])
	}

	fmt.Printf("更新参数: %+v\n", callMng.Para)
	return true
}

// waitForResponse 等待命令响应
func waitForResponse(timeout time.Duration) bool {
	select {
	case <-callMng.respChan:
		return true
	case <-time.After(timeout):
		fmt.Printf("等待响应超时: %v\n", timeout)
		return false
	}
}

func TtyUsb1Uncall() {
	commands := []string{
		QCRMUNCALL,
	}
	TtyUsb1cmd(commands)
}

func TtyUsb1GetInfo() {
	commands := []string{
		CPIN,
		CFUN,
		CIMI,
		ICCID,
		COPS,
		CGSN,
		CSQ,
	}
	TtyUsb1cmd(commands)
}

func TtyUsb1cmd(commands []string) {
	for _, cmd := range commands {
		wcmd := ""
		switch cmd {
		case CPIN, CFUN, COPS:
			wcmd = AT + cmd + QUESTION + CRCN
		default:
			wcmd = AT + cmd + CRCN
		}

		// 写入命令
		_, err := callMng.write.WriteString(wcmd)
		if err != nil {
			log.Printf("写入命令失败: %v", err)
			continue
		}

		// 立即刷新缓冲区
		if err := callMng.write.Flush(); err != nil {
			log.Printf("刷新缓冲区失败: %v", err)
			continue
		}

		fmt.Printf("已发送: %s", wcmd)

		callMng.Cmdmut.Lock()
		callMng.CurrCmd = cmd
		callMng.Recvflag = 1
		callMng.Cmdmut.Unlock()

		for i := 0; i < callMng.Retrytime; i++ {
			// 等待响应，带超时
			if waitForResponse(5 * time.Second) {
				fmt.Printf("命令 %s 执行成功\n", cmd)
				break
			} else {
				fmt.Printf("命令 %s 执行超时\n", cmd)
				// 写入命令
				_, err = callMng.write.WriteString(wcmd)
				if err != nil {
					log.Printf("写入命令失败: %v", err)
					continue
				}
				// 立即刷新缓冲区
				if err = callMng.write.Flush(); err != nil {
					log.Printf("刷新缓冲区失败: %v", err)
					continue
				}
			}
		}

		// 命令间间隔
		time.Sleep(500 * time.Millisecond)
	}
}

func TtyUsb1Call() {
	commands := []string{
		QCRMCALL,
	}
	TtyUsb1cmd(commands)
}

func TtyUsb1Open(devicePath string) error {
	file, err := os.OpenFile(devicePath, os.O_RDWR, 0666)
	if err != nil {
		return fmt.Errorf("无法打开设备: %v", err)
	}

	callMng.usb0file = file
	callMng.read = bufio.NewReader(file)
	callMng.write = bufio.NewWriter(file)
	callMng.respChan = make(chan string, 10) // 缓冲通道
	callMng.stopChan = make(chan bool, 1)

	fmt.Printf("成功打开设备: %s\n", devicePath)
	return nil
}

func TtyUsb1Close() {
	if callMng.isRunning {
		callMng.stopChan <- true
	}

	if callMng.usb0file != nil {
		callMng.usb0file.Close()
	}
}
